﻿#region Using directives
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;
using RacingGame.Graphics;
using RacingGame.Shaders;
using Model = RacingGame.Graphics.Model;
using RacingGame.Landscapes;
#endregion

namespace RacingGame.Tracks
{
    class GuardRail : IDisposable
    {
        #region Constants
        #region Guardrail vertices
        readonly TangentVertex[] GuardRailVertices =
            new TangentVertex[] 
            {
                new TangentVertex(
                    new Vector3(10, 0, -105), new Vector2(0.0f, 1 - 0.442877f),
                    new Vector3(-0.382683f, 0, -0.923880f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(20, 0, -105), new Vector2(0.0f, 1 - 0.432881f),
                    new Vector3(0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-10, 0, -75), new Vector2(0.0f, 1 - 0.402893f),
                    new Vector3(0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-10, 0, -45), new Vector2(0.0f, 1 - 0.372905f),
                    new Vector3(0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(20, 0, -15), new Vector2(0.0f, 1 - 0.342917f),
                    new Vector3(0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(20, 0, 15), new Vector2(0.0f, 1 - 0.312929f),
                    new Vector3(0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-10, 0, 45), new Vector2(0.0f, 1 - 0.282941f),
                    new Vector3(0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-10, 0, 75), new Vector2(0.0f, 1 - 0.252953f),
                    new Vector3(0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(20, 0, 105), new Vector2(0.0f, 1 - 0.222965f),
                    new Vector3(0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(10, 0, 105), new Vector2(0.0f, 1 - 0.212969f),
                    new Vector3(-0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-20, 0, 75), new Vector2(0.0f, 1 - 0.182981f),
                    new Vector3(-0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-20, 0, 45), new Vector2(0.0f, 1 - 0.152993f),
                    new Vector3(-0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(10, 0, 15), new Vector2(0.0f, 1 - 0.123005f),
                    new Vector3(-0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(10, 0, -15), new Vector2(0.0f, 1 - 0.093017f),
                    new Vector3(-0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-20, 0, -45), new Vector2(0.0f, 1 - 0.063029f),
                    new Vector3(-0.923880f, 0, 0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(-20, 0, -75), new Vector2(0.0f, 1 - 0.033041f),
                    new Vector3(-0.923880f, 0, -0.382683f), new Vector3(0, -1, 0)),
                new TangentVertex(
                    new Vector3(10, 0, -105), new Vector2(0.0f, 1 - 0.003053f),
                    new Vector3(-0.382683f, 0, -0.923880f), new Vector3(0, -1, 0)),
            };
        #endregion

        const float CorrectionScale = 0.0019f;

        const float HolderGap = 15.0f;

        const float GuardRailHeight = 1.35f * 1.5f * 0.425f;

        public const float InsideRoadDistance = 0.5f;

        static readonly Vector3 HolderPileCorrectionVector =
            new Vector3(0.225f, 0, 0);
        #endregion

        #region Modes enum
        public enum Modes
        {
            Left,
            Right,
        }
        #endregion

        #region Variables
        TrackVertex[] railPoints = null;

        TangentVertex[] railVertices = null;

        VertexBuffer railVb = null;

        IndexBuffer railIb = null;
        #endregion

        #region Constructor
        public GuardRail(List<TrackVertex> points, Modes mode,
            Landscape landscape)
        {
            #region Generate guardrail points
            railPoints = new TrackVertex[points.Count / 2 + 1];
            for (int num = 0; num < railPoints.Length; num++)
            {
                int pointNum = num * 2;
                if (pointNum >= points.Count - 1)
                    pointNum = points.Count - 1;
                if (mode == Modes.Left)
                {
                    railPoints[num] = points[pointNum].LeftTrackVertex;
                    railPoints[num].right = -railPoints[num].right;
                    railPoints[num].dir = -railPoints[num].dir;
                    railPoints[num].pos -=
                        railPoints[num].right * InsideRoadDistance;
                }
                else
                {
                    railPoints[num] = points[pointNum].RightTrackVertex;
                    railPoints[num].pos -=
                        railPoints[num].right * InsideRoadDistance;
                }
            }
            #endregion

            #region Generate vertex buffer
            railVertices = 
                new TangentVertex[railPoints.Length * GuardRailVertices.Length];

            float uTexValue = 0.5f;
            float lastHoderGap = 0;
            for (int num = 0; num < railPoints.Length; num++)
            {
                Vector3 right = railPoints[num].right;
                Vector3 dir = railPoints[num].dir;
                Vector3 up = railPoints[num].up;

                Matrix pointSpace = Matrix.Identity;
                pointSpace.M11 = right.X;
                pointSpace.M12 = right.Y;
                pointSpace.M13 = right.Z;
                pointSpace.M21 = dir.X;
                pointSpace.M22 = dir.Y;
                pointSpace.M23 = dir.Z;
                pointSpace.M31 = up.X;
                pointSpace.M32 = up.Y;
                pointSpace.M33 = up.Z;

                Vector3 localPos = railPoints[num].pos;

                localPos += up * GuardRailHeight;

                for (int i = 0; i < GuardRailVertices.Length; i++)
                {
                    Vector3 pos = Vector3.Transform(
                        GuardRailVertices[i].pos * CorrectionScale, 
                        pointSpace * Matrix.CreateTranslation(localPos));

                    Vector3 normal = Vector3.TransformNormal(
                        (mode == Modes.Left ? -1 * 1) *
                        GuardRailVertices[i].normal,
                        pointSpace);
                    Vector3 tangent = Vector3.TransformNormal(
                        -GuardRailVertices[i].tangent,
                        pointSpace);

                    railVertices[num * GuardRailVertices.Length + i] =
                        new TangentVertex(pos,
                            uTexValue, GuardRailVertices[i].V,
                            normal, tangent);
                }

                float distance = Vector3.Distance(
                    railPoints[(num + 1) % railPoints.Length].pos, railPoints[num].pos);
            }
            #endregion
        }
        #endregion
    }
}
